package org.example.user.context;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

/**
 * 组件上下文，维护一个微型bean容器（JNDI的Naming上下文）{@link Context}
 *
 * @author hrz
 * @since 2021/3/12 0012
 */
public class ComponentContext {

    /**
     * JNDI的Naming上下文的根路径
     */
    private static final String COMPONENT_ENV_CONTEXT_NAME = "java:comp/env";

    /**
     * 容器名称
     */
    public static final String CONTEXT_NAME = ComponentContext.class.getName();

    /**
     * Servlet容器的上下文
     *
     * 假设一个 Tomcat JVM 进程，三个 Web Apps，会不会相互冲突？（不会冲突）
     * static 字段是 JVM 缓存吗？（是 ClassLoader 缓存）
     */
    private static ServletContext servletContext;

    /**
     * JNDI的Naming上下文
     */
    private Context envContext;

    public void init(ServletContext servletContext) throws NamingException {
        ComponentContext.servletContext = servletContext;
        servletContext.setAttribute(CONTEXT_NAME, this);
        initEnvContext();
    }

    public static ComponentContext getInstance() {
        return (ComponentContext) servletContext.getAttribute(CONTEXT_NAME);
    }

    private void initEnvContext() throws NamingException {
        if (this.envContext != null) {
            return;
        }
        Context context = new InitialContext();
        this.envContext = (Context) context.lookup(COMPONENT_ENV_CONTEXT_NAME);
    }

    public <T> T lookComponent(String name) throws NamingException {
        return (T) this.envContext.lookup(name);
    }

}
